package mspbots.autotask.client.core.data.contacts;

import com.fasterxml.jackson.databind.JsonNode;
import mspbots.autotask.client.core.AbstractToolsUtil;
import mspbots.autotask.client.core.BaseSyncService;
import mspbots.autotask.client.core.client.ClientProperties;
import mspbots.autotask.client.core.client.ClientUtils;
import mspbots.autotask.common.*;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * mspbots.core.autotask.core.companies.CompaniesServiceImpl
 *
 * @author <a href="https://github.com/vnobo">Alex bob</a>
 * @date Created by 2020/8/4
 */
@Service
public class ContactsServiceImpl extends AbstractToolsUtil implements BaseSyncService {

    private final String QUERY_REQUEST_PATH = "/V1.0/Contacts/query";

    public Mono<JsonNode> find(Long tenantId, QueryBody queryBody, URI pageUrl) {
        ResultSync resultSync = ResultSync.withDefault("CONTACTS-FIND");
        return super.loadProperties(tenantId)
                .subscriberContext(ctx -> ctx.put("resultSync", resultSync))
                .flatMap(properties -> this.find(properties, queryBody, pageUrl));
    }

    public Mono<JsonNode> count(Long tenantId, QueryBody queryBody) {
        ResultSync resultSync = ResultSync.withDefault("CONTACTS-COUNT");
        return super.loadProperties(tenantId)
                .subscriberContext(ctx -> ctx.put("resultSync", resultSync))
                .flatMap(properties -> this.count(properties, queryBody));
    }

    @Override
    public Mono<Void> syncSlow(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("CONTACTS-SYNC");
        return this.dateCacheFilterFetch(properties)
                .subscriberContext(ctx -> ctx.put("resultSync", resultSync))
                .doOnNext(result -> this.syncResult(properties.getTenantId(), resultSync.getRequestId(), result))
                .then();
    }

    @Override
    public Mono<Void> syncInformation(ClientProperties properties) {
        ResultSync resultInfoSync = ResultSync.withDefault("CONTACTS-ENTITY-INFORMATION");
        return this.entityInformation(properties)
                .subscriberContext(ctx -> ctx.put("resultSync", resultInfoSync))
                .doOnNext(result -> this.syncInformationResult(properties.getTenantId(),
                        resultInfoSync.getRequestId(), result))
                .then();
    }


    private void syncResult(Long tenantId, UUID id, JsonNode resultNode) {
        this.sendEntity(RabbitKeys.CONTACTS_SYNC_QUEUE_KEY, ResultMsg.builder()
                .requestId(id).id(resultNode.get("id").longValue())
                .action("none").entity(resultNode).tenantId(tenantId)
                .syncDate(LocalDateTime.now()).build());
    }

    private Flux<JsonNode> dateCacheFilterFetch(ClientProperties properties) {
        String redisAnchorKey = RedisKeys.CONTACTS_ANCHOR_REDIS_KEY_PREFIX + properties.getTenantId();
        return super.readAnchorTime(redisAnchorKey)
                .flatMapMany(syncTime -> this.fetch(properties, QueryBody.withFilter(FilterExpression.builder()
                        .op("gt").field("lastActivityDate").value(syncTime).build())))
                .doOnNext(user -> super.recordAnchorTime(redisAnchorKey, user.get("lastActivityDate").textValue()));
    }

    private Flux<JsonNode> fetch(ClientProperties properties, QueryBody queryBody) {
        return super.autoTaskClient
                .fetch(ClientUtils.builderRequestUrl(properties.getBaseUrl(), QUERY_REQUEST_PATH), queryBody)
                .subscriberContext(ctx -> ctx.put("properties", properties));
    }

    private Mono<JsonNode> find(ClientProperties properties, QueryBody queryBody, URI pageUrl) {
        if (ObjectUtils.isEmpty(pageUrl)) {
            pageUrl = ClientUtils.builderRequestUrl(properties.getBaseUrl(), QUERY_REQUEST_PATH);
        }
        return super.autoTaskClient
                .post(pageUrl, queryBody)
                .subscriberContext(ctx -> ctx.put("properties", properties));
    }

    private Mono<JsonNode> count(ClientProperties properties, QueryBody queryBody) {
        queryBody.setMaxRecords(0);
        String countRequestPath = "/V1.0/Contacts/query/count";
        return super.autoTaskClient.post(ClientUtils.builderRequestUrl(properties.getBaseUrl(), countRequestPath), queryBody)
                .subscriberContext(ctx -> ctx.put("properties", properties));
    }


    private void syncInformationResult(Long tenantId, UUID id, JsonNode resultNode) {
        this.sendEntity(RabbitKeys.INFORMATION_SYNC_QUEUE_KEY, ResultMsg.builder()
                .requestId(id).action("Contacts")
                .entity(resultNode).tenantId(tenantId)
                .syncDate(LocalDateTime.now()).build());
    }

    private Flux<JsonNode> entityInformation(ClientProperties properties) {
        return super.autoTaskClient.get(ClientUtils.builderRequestUrl(properties.getBaseUrl(),
                "/V1.0/Contacts/entityInformation/fields"))
                .subscriberContext(ctx -> ctx.put("properties", properties))
                .flatMapMany(jsonNode -> Flux.fromIterable(jsonNode.withArray("fields")));
    }
}
